import React, { ChangeEvent, createRef } from 'react';
import {
  DataTable,
  DataTableRowClickEvent,
  DataTableSelectEvent,
  DataTableUnselectEvent,
  DataTablePageEvent,
  DataTableSortEvent,
  SortOrder,
} from 'primereact/datatable';
import { Column } from 'primereact/column';
import { ProgressBar } from 'primereact/progressbar';
import { OverlayPanel } from 'primereact/overlaypanel';
import { InputProps } from "../Input";
import { InputFactory } from "../InputFactory";

import Table, { OrderBy, TableState, TableProps } from './../Table';
import ExportButton from '../ExportButton';
import { dateToEUFormat, datetimeToEUFormat } from "../Inputs/DateTime";

export interface PrimeTableProps extends TableProps {
  selectionMode?: 'single' | 'multiple' | undefined,
}

/**
 * [Description PrimeTableState]
 */
export interface PrimeTableState extends TableState {
  selection: any,
}

export default class PrimeTable<P, S> extends Table<PrimeTableProps, PrimeTableState> {
  state: PrimeTableState;
  props: PrimeTableProps;

  dt = createRef<DataTable<any[]>>();

  constructor(props: TableProps) {
    super(props);

    this.state = {
      ...this.state,
      selection: [],
    };
  }

  getTableProps(): Object {
    const sortOrders = {'asc': 1, 'desc': -1};

    return {
      ref: this.dt,
      value: this.state.data?.data,
      // editMode: 'row',
      compareSelectionBy: 'equals',
      dataKey: "id",
      first: (this.state.page - 1) * this.state.itemsPerPage,
      paginator: true,
      lazy: true,
      rows: this.state.itemsPerPage,
      totalRecords: this.state.data?.total,
      rowsPerPageOptions: [5, 15, 30, 50, 100, 200, 500, 1000],
      paginatorTemplate: "FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown",
      currentPageReportTemplate: "{first}-{last} / {totalRecords}",
      onRowClick: (data: DataTableRowClickEvent) => this.onRowClick(data.data.id as number),
      onRowSelect: (event: DataTableSelectEvent) => this.onRowSelect(event),
      onRowUnselect: (event: DataTableUnselectEvent) => this.onRowUnselect(event),
      onPage: (event: DataTablePageEvent) => this.onPaginationChangeCustom(event),
      onSort: (event: DataTableSortEvent) => this.onOrderByChangeCustom(event),
      sortOrder: sortOrders[this.state.orderBy?.direction ?? 'asc'],
      sortField: this.state.orderBy?.field,
      rowClassName: (rowData: any) => this.rowClassName(rowData),
      stripedRows: true,
      //globalFilter={globalFilter}
      //header={header}
      emptyMessage: globalThis.app.dictionary['PrimeTable/emptyMessage'] ?? 'No data.',
      dragSelection: true,
      selectAll: true,
      metaKeySelection: true,
      selection: this.state.selection,
      selectionMode: (this.props.selectionMode == 'single' ? 'radiobutton': (this.props.selectionMode == 'multiple' ? 'checkbox' : null)),
      onSelectionChange: (event: any) => {
        this.setState(
          {selection: event.value} as PrimeTableState,
          function() {
            this.onSelectionChange(event);
          }
        )
      }
    };
  }

  onSelectionChange(event: any) {
    // to be overriden
  }

  onPaginationChangeCustom(event: DataTablePageEvent) {
    const page: number = (event.page ?? 0) + 1;
    const itemsPerPage: number = event.rows;
    this.onPaginationChange(page, itemsPerPage);
  }

  onOrderByChangeCustom(event: DataTableSortEvent) {
    let orderBy: OrderBy | null = null;

    // Icons in PrimeTable changing
    // 1 == ASC
    // -1 == DESC
    // null == neutral icons
    if (event.sortField == this.state.orderBy?.field) {
      orderBy = {
        field: event.sortField,
        direction: event.sortOrder === 1 ? 'asc' : 'desc',
      };
    } else {
      orderBy = {
        field: event.sortField,
        direction: 'asc',
      };
    }

    console.log(event, orderBy);

    this.onOrderByChange(orderBy);
  }

  onRowSelect(event: DataTableSelectEvent) {
    // to be overriden
  }

  onRowUnselect(event: DataTableUnselectEvent) {
    // to be overriden
  }

  /*
   * Render body for Column (PrimeReact column)
   */
  renderCell(columnName: string, column: any, data: any, options: any) {
    const columnValue: any = data[columnName];
    const enumValues = column.enumValues;
    const inputProps = {
      uid: this.props.uid + '_' + columnName,
      columnName: columnName,
      params: column,
      value: columnValue,
      showInlineEditingButtons: true,
    };

    if (enumValues) return <span style={{fontSize: '10px'}}>{enumValues[columnValue]}</span>;

    let cellValueElement: JSX.Element|null = null;

    if (columnValue === null) {
      cellValueElement = null;
    } else {
      switch (column.type) {
        case 'int':
          cellValueElement = <div className="text-right">
            {columnValue}
            {column.unit ? ' ' + column.unit : ''}
          </div>;
        break;
        case 'float':
          cellValueElement = <div className="text-right">
            {columnValue}
            {column.unit ? ' ' + column.unit : ''}
          </div>;
        break;
        case 'color':
          cellValueElement = <div
            style={{ width: '20px', height: '20px', background: columnValue }} 
            className="rounded"
          />;
        break;
        case 'image':
          if (!columnValue) cellValueElement = <i className="fas fa-image" style={{color: '#e3e6f0'}}></i>
          else {
            cellValueElement = <img 
              style={{ width: '30px', height: '30px' }}
              src={this.state.folderUrl + "/" + columnValue}
              className="rounded"
            />;
          }
        break;
        case 'lookup':
          cellValueElement = <span style={{
            color: '#2d4a8a'
          }}>{columnValue?.lookupSqlValue}</span>;
        break;
        case 'enum':
          const enumValues = column.enumValues;
          if (enumValues) cellValueElement = enumValues[columnValue];
        break;
        case 'bool':
        case 'boolean':
          if (columnValue) cellValueElement = <span className="text-success" style={{fontSize: '1.2em'}}>✓</span>
          else cellValueElement = <span className="text-danger" style={{fontSize: '1.2em'}}>✕</span>
        break;
        case 'date':
          cellValueElement = <span>{dateToEUFormat(columnValue)}</span>;
        break;
        case 'datetime':
          cellValueElement = <span>{datetimeToEUFormat(columnValue)}</span>;
        break;
        case 'tags':
          cellValueElement = <>
            {columnValue.map((item: any) => {
              if (!column.dataKey) return <></>;
              return <span className="badge badge-info mx-1" key={item.id}>{item[column.dataKey]}</span>;
            })}
          </>
        break;
        default:
          cellValueElement = columnValue;
        break;
      }

      if (cellValueElement === <></>) {
        cellValueElement = columnValue;
      }
    }

    let op = createRef<OverlayPanel>();

    let cellEditorElement: JSX.Element = InputFactory({
      ...inputProps,
      isInlineEditing: true,
      onInlineEditCancel: () => { op.current?.hide(); }
    });

    return <>
      {cellValueElement}
      {this.state.inlineEditingEnabled ? <>
        <i
          className="inline-edit-icon fas fa-pencil-alt text-xs"
          onClick={(e) => { e.stopPropagation(); op.current?.toggle(e); }}
        ></i>
        <OverlayPanel ref={op} onClick={(e) => { e.stopPropagation(); }}>
          {cellEditorElement}
        </OverlayPanel>
      </> : null}
    </>;
  }

  renderColumns(): JSX.Element[] {
    let columns: JSX.Element[] = [];

    if (this.props.selectionMode) {
      columns.push(<Column selectionMode={this.props.selectionMode}></Column>);
    }
    
    Object.keys(this.state.columns).map((columnName: string) => {
      const column: any = this.state.columns[columnName];
      columns.push(<Column
        key={columnName}
        field={columnName}
        header={column.title}
        body={(data: any, options: any) => {
          return (
            <div className={(column.cssClass ?? '') + ' ' + this.cellClassName(columnName, data)} style={column.cssStyle}>
              {this.renderCell(columnName, column, data, options)}
            </div>
          );
        }}
        style={{ width: 'auto' }}
        sortable
      ></Column>);
    });

    columns.push(<Column
      key='__actions'
      field='__actions'
      header=''
      body={(data: any, options: any) => {
        return (
          <button className="btn btn-small btn-transparent">
            <span className="icon"><i className="fas fa-ellipsis-h"></i></span>
          </button>
        );
      }}
      style={{ width: 'auto' }}
    ></Column>);

    return columns;
  }

  cellClassName(columnName: string, rowData: any) {
    return ''; // rowData.id % 2 === 0 ? '' : 'bg-light';
  }

  rowClassName(rowData: any): string {
    return rowData.id === this.state.formId ? 'highlighted' : '';
  }

  renderAddButton(): JSX.Element {
    return (
      <button
        className="btn btn-primary btn-icon-split"
        onClick={() => this.onAddClick()}
      >
        <span className="icon"><i className="fas fa-plus"/></span>
        <span className="text">{this.state.addButtonText}</span>
      </button>
    );
  }

  renderHeaderButtons(): JSX.Element {
    return this.state.canCreate ? this.renderAddButton() : <></>;
  }

  renderHeader(): JSX.Element {
    return <div className="table-header">
      <div className="table-header-left">
        {this.renderHeaderButtons()}
      </div>

      {this.state.title ? <div className="table-header-title">{this.state.title}</div> : null}

      <div className="table-header-right">
        <input 
          className="table-header-search"
          type="search"
          placeholder="Start typing to search..."
          value={this.state.search}
          onChange={(event: ChangeEvent<HTMLInputElement>) => this.onSearchChange(event.target.value)}
        />
      </div>

      {/* <div className="dropdown no-arrow">
        <button 
          className="btn btn-light dropdown-toggle" 
          type="button"
          data-toggle="dropdown"
          aria-haspopup="true"
          aria-expanded="false"
        >
          <i className="fas fa-ellipsis-v"/>
        </button>
        <div className="dropdown-menu">
          <ExportButton
            uid={this.props.uid}
            exportType="image"
            exportElementId={'adios-table-prime-body-' + this.props.uid}
            exportFileName={this.state.title}
            text="Save as image"
            icon="fas fa-file-export mr-2"
            customCssClass="dropdown-item"
          />
          <button className="dropdown-item" type="button">
            <i className="fas fa-file-export mr-2"/> Exportovať do CSV
          </button>
          <button className="dropdown-item" type="button">
            <i className="fas fa-print mr-2"/> Tlačiť
          </button>
        </div>
      </div> */}
    </div>
  }

  render() {
    if (!this.state.data || !this.state.columns) {
      return <ProgressBar mode="indeterminate" style={{ height: '8px' }}></ProgressBar>;
    }

    return (
      <>
        {this.renderFormModal()}

        <div
          id={"adios-table-prime-" + this.props.uid}
          className={"adios component table " + (this.state.loadingInProgress ? "loading" : "")}
        >
          {this.state.showHeader ? this.renderHeader() : ''}

          <div className="table-body" id={"adios-table-prime-body-" + this.props.uid}>
            <DataTable {...this.getTableProps()}>
              {this.renderColumns()}
            </DataTable>
          </div>
        </div>
      </>
    );
  }
}

